<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>长沙市图书馆查询系统</title>
    <script src="./ol.js"></script>
    <link rel="stylesheet" href="./ol.css" />
    <script src="./ol-ext.js"></script>
    <link rel="stylesheet" href="./ol-ext.css" />
    <!-- 引入 layui.css -->
    <link href="./layui/css/layui.css" rel="stylesheet" />

    <!-- 引入 layui.js -->
    <script src="./layui/layui.js"></script>
    <style>
      html,
      body,
      #map {
        height: 100%;
        width: 100%;
        padding: 0;
        margin: 0;
        overflow: hidden;
      }
      #map {
        height: calc(100vh - 60px);
      }
      #mouse-position {
        position: absolute;
        top: 8px;
        right: 30px;
        z-index: 999;
        padding: 5px;
        width: 200px;
        font-size: 20px;
        font-weight: bold;
      }
    </style>
  </head>
  <body>
    <ul class="layui-nav layui-bg-gray">
      <li class="layui-nav-item">
        <b style="font-size: 20px">长沙市图书馆查询系统</b>
      </li>
      <li class="layui-nav-item">
        <a href="javascript:;">测量</a>
        <dl class="layui-nav-child">
          <dd>
            <a href="javascript:;" onclick="area()">面积测量</a>
          </dd>
          <dd>
            <a href="javascript:;" onclick="distance()">距离测量</a>
          </dd>
        </dl>
      </li>
      <li class="layui-nav-item">
        <a onclick="get_location()">定位</a>
      </li>
      <li class="layui-nav-item">
        <a onclick="bbox_search()">空间查询</a>
      </li>
      <li class="layui-nav-item">
        <a onclick="goToPath()">路径规划</a>
      </li>
      <li class="layui-nav-item">
        <a onclick="buffer()">建立缓冲区</a>
      </li>
      <li class="layui-nav-item">
        <a onclick="bufferSearch()">缓冲区查询</a>
      </li>
    </ul>

    <div id="map">
      <div id="mouse-position"></div>
    </div>
  </body>
  <script>
    let drawLayer = new ol.layer.Vector({
      title: "绘制图层",
      source: new ol.source.Vector(),
    });
    let gd_img = new ol.layer.Tile({
      title: "高德影像",
      source: new ol.source.XYZ({
        url: "http://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
      }),
      visible: false,
    });
    let gd_vec = new ol.layer.Tile({
      title: "高德地图",
      source: new ol.source.XYZ({
        url: "http://webst01.is.autonavi.com/appmaptile?style=7&x={x}&y={y}&z={z}",
      }),
    });
    var vector = new ol.layer.Vector({
      title: "图书馆",
      source: new ol.source.Vector({
        format: new ol.format.GeoJSON(),
        url: "./data.geojson",
      }),
      //图标
      style: new ol.style.Style({
        image: new ol.style.Icon({
          src: "./library.png",
          scale: 0.2,
        }),
      }),
    });
    var map = new ol.Map({
      target: "map",
      layers: [
        gd_vec,
        gd_img,
        drawLayer,
        vector,
        //热力图
        new ol.layer.Heatmap({
          title: "热力图",
          visible: false,
          source: new ol.source.Vector({
            url: "./data.geojson",
            format: new ol.format.GeoJSON(),
          }),
          blur: 20,
          radius: 15,
          gradient: ["#00f", "#0ff", "#0f0", "#ff0", "#f00"],
        }),
      ],
      view: new ol.View({
        //长沙
        center: ol.proj.fromLonLat([112.982279, 28.19409]),
        zoom: 12,
        maxZoom: 18,
      }),
    });
    //鹰眼
    var overviewMapControl = new ol.control.OverviewMap({
      //鹰眼控件的位置
      collapsed: false,
      layers: [
        new ol.layer.Tile({
          title: "高德地图",
          source: new ol.source.XYZ({
            url: "http://webst01.is.autonavi.com/appmaptile?style=7&x={x}&y={y}&z={z}",
          }),
        }),
      ],
    });
    map.addControl(overviewMapControl);
    var selecti = new ol.interaction.Select({
      hitTolerance: 5,
      condition: ol.events.condition.singleClick,
      layers: [vector],
    });
    map.addInteraction(selecti);
    var popup = new ol.Overlay.PopupFeature({
      popupClass: "default anim",
      select: selecti,
      canFix: true,
    });
    map.addOverlay(popup);

    // Set the control grid reference
    var search = new ol.control.SearchFeature({
      //target: $(".options").get(0),
      source: vector.getSource(),
      property: "name",
      sort: function (f1, f2) {
        if (search.getSearchString(f1) < search.getSearchString(f2)) return -1;
        if (search.getSearchString(f1) > search.getSearchString(f2)) return 1;
        return 0;
      },
    });
    map.addControl(search);
    // selecti feature when click on the reference index
    search.on("select", function (e) {
      console.log(e);
      selecti.getFeatures().clear();
      selecti.getFeatures().push(e.search);
      var p = e.search.getGeometry().getFirstCoordinate();
      popup.show(p, e.search);
      map.getView().animate({ center: p });
    });

    document.getElementsByClassName("search")[0].placeholder =
      "请输入图书馆名称";
    map.addControl(new ol.control.LayerSwitcher());

    //比例尺
    var scaleLineControl = new ol.control.ScaleLine();
    map.addControl(scaleLineControl);
    //ZoomSlider
    var zoomSliderControl = new ol.control.ZoomSlider();
    map.addControl(zoomSliderControl);

    //ol.control.MousePosition
    var mousePositionControl = new ol.control.MousePosition({
      coordinateFormat: ol.coordinate.createStringXY(4),
      projection: "EPSG:4326",
      target: document.getElementById("mouse-position"),
      undefinedHTML: "&nbsp;",
    });
    map.addControl(mousePositionControl);
    //FullScreen
    var fullScreenControl = new ol.control.FullScreen();
    map.addControl(fullScreenControl);

 

    //设置地图容器放置位置
    let container = document.getElementById("map"); //创建地图容器 //探查半径
    let radius = 75; //添加键盘按下事件监听，用来控制探查范围的大小
    document.addEventListener("keydown", function (evt) {
      if (evt.which == 38) {
        radius = Math.min(radius + 5, 150); //map.render();
        evt.preventDefault();
      } else if (evt.which == 40) {
        radius = Math.max(radius - 5, 25);
        map.render();
        evt.preventDefault();
      }
    }); // 实时得到鼠标的像素位置
    let mousePosition = null;
    container.addEventListener("mousemove", function (event) {
      mousePosition = map.getEventPixel(event);
      map.render();
    });
    container.addEventListener("mouseout", function () {
      mousePosition = null;
      map.render();
    }); // 在渲染层之前,做剪裁
    gd_img.on("prerender", function (event) {
      let ctx = event.context;
      let pixelRatio = event.frameState.pixelRatio;
      ctx.save();
      ctx.beginPath();
      if (mousePosition) {
        //只显示一个围绕着鼠标的圆圈
        ctx.arc(
          mousePosition[0] * pixelRatio,
          mousePosition[1] * pixelRatio,
          radius * pixelRatio,
          0,
          2 * Math.PI
        );
        ctx.lineWidth = 5 * pixelRatio;
        ctx.strokeStyle = "rgba(0,0,0,0.5)";
        ctx.stroke();
      }
      ctx.clip();
    }); // 呈现层后,恢复画布的背景
    gd_img.on("postrender", function (event) {
      let ctx = event.context;
      ctx.restore();
    });
     function distance() {
      layer.msg("请在地图上绘制线");
      var drawLine = new ol.interaction.Draw({
        type: "LineString",
        source: drawLayer.getSource(),
      });
      map.addInteraction(drawLine);

      // Add a tooltip
      var tooltip = new ol.Overlay.Tooltip();
      map.addOverlay(tooltip);

      // Set feature on drawstart
      drawLine.on("drawstart", tooltip.setFeature.bind(tooltip));
      // Remove feature on finish 并且移除drawLine
      drawLine.on(["change:active", "drawend"], function (e) {
        tooltip.removeFeature(e);
        map.removeInteraction(drawLine);
      });
    }
    function area() {
      layer.msg("请在地图上绘制多边形");
      var drawPolygon = new ol.interaction.Draw({
        type: "Polygon",
        source: drawLayer.getSource(),
      });
      map.addInteraction(drawPolygon);

      // Add a tooltip
      var tooltip = new ol.Overlay.Tooltip();
      map.addOverlay(tooltip);

      // Set feature on drawstart
      drawPolygon.on("drawstart", tooltip.setFeature.bind(tooltip));
      // Remove feature on finish 并且移除drawPolygon
      drawPolygon.on(["change:active", "drawend"], function (e) {
        tooltip.removeFeature(e);
        map.removeInteraction(drawPolygon);
      });
    }
    function bbox_search() {
      layer.msg("请在地图上绘制矩形");
      //绘制矩形，显示矩形范围内的要素
      var draw = new ol.interaction.Draw({
        source: drawLayer.getSource(),
        type: "Circle",
        geometryFunction: ol.interaction.Draw.createBox(),
      });
      map.addInteraction(draw);
      draw.on("drawend", function (evt) {
        var extent = evt.feature.getGeometry().getExtent();
        var features = vector.getSource().getFeaturesInExtent(extent);

        //用layui的弹出框表格显示查询结果
        layer.open({
          type: 1,
          title: "查询结果",
          area: ["500px", "400px"],
          content: `<div style="padding:20px"><table class="layui-table">
            <colgroup>
              <col width="150">
              <col width="150">
            </colgroup>
            <thead>
              <tr>
                <th>图书馆名称</th>
                <th>图书馆类型</th>
                <th>图书馆地址</th>
              </tr>
            </thead>
            <tbody>
              ${features
                .map((feature) => {
                  return `<tr>
                  <td>${feature.get("name")}</td>
                  <td>${feature.get("type")}</td>
                  <td>${feature.get("address")}</td>
                </tr>`;
                })
                .join("")}
            </tbody>
          </table></div>`,
        });

        map.removeInteraction(draw);
      });
    }
    function get_location() {
      //获取当前位置,在地图上显示
      try {
        navigator.geolocation.getCurrentPosition(function (position) {
          var pos = ol.proj.fromLonLat([
            position.coords.longitude,
            position.coords.latitude,
          ]);
          var point = new ol.geom.Point(pos);
          var feature = new ol.Feature(point);
          //红色的点,并且上方显示我的位置文字
          feature.setStyle(
            new ol.style.Style({
              image: new ol.style.Circle({
                radius: 4,
                fill: new ol.style.Fill({
                  color: "red",
                }),
              }),
              text: new ol.style.Text({
                text: "我的位置",
                offsetY: -15,
                fill: new ol.style.Fill({
                  color: "red",
                }),
                //加粗
                font: "bold 14px Arial",
              }),
            })
          );
          drawLayer.getSource().addFeature(feature);
          map.getView().setCenter(pos);
          map.getView().setZoom(15);
        });
      } catch (error) {
        console.log(error);
      }
    }
    const goToPath = () => {
      //检查selecti是否有选中的feature
      if (selecti.getFeatures().getLength() === 0) {
        layui.layer.msg("请先选择一个图书馆");
        return;
      }
      //获取选中的feature
      const feature = selecti.getFeatures().item(0);
      //获取feature的坐标
      const coordinate = feature.getGeometry().getCoordinates();
      //获取feature的名称
      const name = feature.getProperties().name;
      //请在地图上标记起点
      layui.layer.msg("请在地图上标记起点");
      //添加一个交互
      const draw = new ol.interaction.Draw({
        source: new ol.source.Vector(),
        type: "Point",
      });
      map.addInteraction(draw);
      //监听绘制结束事件
      draw.on("drawend", (e) => {
        //获取绘制的feature
        const endFeature = e.feature;
        //获取绘制的feature的坐标
        const endCoordinate = endFeature.getGeometry().getCoordinates();
        //获取绘制的feature的名称
        const endName = "终点";
        //移除绘制交互
        map.removeInteraction(draw);
        layer.open({
          title: "路径规划结果",
          type: 2,
          shade: false,
          area: ["1000px", "600px"],
          maxmin: true,
          content: `/car.html?destination=${ol.proj
            .toLonLat(coordinate)
            .toString()}&origin=${ol.proj.toLonLat(endCoordinate).toString()}`,
          zIndex: layer.zIndex, //重点1
          success: function (layero) {
            layer.setTop(layero); //重点2
          },
        });
      });
    };
    const buffer = () => {
      //判断是否有选中的feature
      if (selecti.getFeatures().getLength() === 0) {
        layui.layer.msg("请先选择一个图书馆");
        return;
      }
      //获取选中的feature
      const feature = selecti.getFeatures().item(0);
      //获取feature的坐标
      const coordinate = feature.getGeometry().getCoordinates();
      //打开弹出，用户输入缓冲区半径
      layer.prompt(
        { title: "请输入缓冲区半径(单位：米)" },
        function (value, index, elem) {
          //判断输入是否为正整数
          if (!/^[1-9]\d*$/.test(value)) {
            layui.layer.msg("请输入正整数");
            return;
          }
          //关闭弹出
          layer.close(index);
          //创建一个圆形
          const circle = new ol.geom.Circle(coordinate, parseInt(value));
          const circleFeature = new ol.Feature(circle);
          //边框为blue
          circleFeature.setStyle(
            new ol.style.Style({
              stroke: new ol.style.Stroke({
                color: "blue",
                width: 2,
              }),
              //填充为蓝色透明
              fill: new ol.style.Fill({
                color: "rgba(0, 0, 255, 0.2)",
              }),
            })
          );

          //添加到绘制图层
          drawLayer.getSource().addFeature(circleFeature);

          //fit
          map.getView().fit(circleFeature.getGeometry(), {
            padding: [10, 10, 10, 10],
          });
        }
      );
    };
    const bufferSearch = () => {
      //在地图上随意点击一个点，输入缓冲区半径，查询缓冲区内的图书馆，显示查询结果
      layer.msg("请在地图上随意点击一个点");
      //添加一个交互
      const draw = new ol.interaction.Draw({
        source: new ol.source.Vector(),
        type: "Point",
      });
      map.addInteraction(draw);
      //监听绘制结束事件
      draw.on("drawend", (e) => {
        //获取绘制的feature
        const endFeature = e.feature;
        //获取绘制的feature的坐标
        const endCoordinate = endFeature.getGeometry().getCoordinates();
        //移除绘制交互
        map.removeInteraction(draw);
        //打开弹出，用户输入缓冲区半径
        layer.prompt(
          { title: "请输入缓冲区半径(单位：米)" },
          function (value, index, elem) {
            //判断输入是否为正整数
            if (!/^[1-9]\d*$/.test(value)) {
              layui.layer.msg("请输入正整数");
              return;
            }
            //关闭弹出
            layer.close(index);
            //创建一个圆形
            const circle = new ol.geom.Circle(endCoordinate, parseInt(value));
            const circleFeature = new ol.Feature(circle);
            //边框为blue
            circleFeature.setStyle(
              new ol.style.Style({
                stroke: new ol.style.Stroke({
                  color: "blue",
                  width: 2,
                }),
                //填充为蓝色透明
                fill: new ol.style.Fill({
                  color: "rgba(0, 0, 255, 0.2)",
                }),
              })
            );
            //添加到绘制图层
            drawLayer.getSource().addFeature(circleFeature);
            //获取缓冲区范围
            const extent = circle.getExtent();
            //获取缓冲区范围内的要素
            const features = vector.getSource().getFeaturesInExtent(extent);
            //按距离从远到近排序
            features.sort((a, b) => {
              return (
                ol.sphere.getDistance(
                  circle.getCenter(),
                  a.getGeometry().getFirstCoordinate()
                ) -
                ol.sphere.getDistance(
                  circle.getCenter(),
                  b.getGeometry().getFirstCoordinate()
                )
              );
            });

            //用layui的弹出框表格显示查询结果
            layer.open({
              type: 1,
              title: "查询结果",
              area: ["500px", "400px"],
              content: `<div style="padding:20px"><table class="layui-table">
                <colgroup>
                  <col width="150">
                  <col width="150">
                </colgroup>
                <thead>
                  <tr>
                    <th>图书馆名称</th>
                    <th>图书馆类型</th>
                    <th>图书馆地址</th>
                  </tr>
                </thead>
                <tbody>
                  ${features
                    .map((feature) => {
                      return `<tr>
                    <td>${feature.get("name")}</td>
                    <td>${feature.get("type")}</td>
                    <td>${feature.get("address")}</td>
                  </tr>`;
                    })
                    .join("")}
                </tbody>
              </table></div>`,
            });

            //fit
            map.getView().fit(circleFeature.getGeometry(), {
              padding: [10, 10, 10, 10],
            });
          }
        );
      });
    };
  </script>
</html>
